# -*- coding: utf-8 -*-


import os, commands
import math
import _feature_  as feature
import _read_xml_ as read_xml
import  _conf_    as conf


# -----------------------------------------------------------------------------
# global-variables
# -----------------------------------------------------------------------------

fn_dev_f    = ''
fn_test_f   = ''
fn_model    = ''
fn_dev_log  = ''
fn_test_log = ''


# -----------------------------------------------------------------------------
# initialize global-variables using _conf
# -----------------------------------------------------------------------------
def initialize():
    global fn_dev_f, fn_test_f, fn_model, fn_dev_log, fn_test_log

    fn_dev_f    = '%s/dev.f'     % conf.log_dir_name
    fn_test_f   = '%s/test.f'    % conf.log_dir_name
    fn_model    = '%s/out.model' % conf.log_dir_name
    fn_dev_log  = '%s/dev.log'   % conf.log_dir_name
    fn_test_log = '%s/test.log'  % conf.log_dir_name


# -----------------------------------------------------------------------------
# convert result of classias to format of RITE2.
# -----------------------------------------------------------------------------
def convertClassias2RITE(classias_out, data_list, is_mc):
    out = []
    
    indices_b = feature.getIndicesLabelB(data_list)
    num_b     = 0
    label_p   = None
    score_p   = None

    for i, line in enumerate(classias_out.splitlines()):
        spl = line.split(':')
        score = float(spl[1])
        
        if not is_mc:
            label = 'Y' if spl[0]=='+1' else 'N'

            if conf.do_apply_sigmoid:
                score = 1.0 / (1.0 + math.exp(-1.0 * score)) # --- sigmoid
                if label == 'N':
                    score = 1.0 - score
                
        else:
            label = spl[0]
            score = float(spl[1])

            if label_p == None and (i-num_b) in indices_b:
                label_p = label
                score_p = score
                continue

            elif label_p != None:
                if label == 'F' and label_p == 'F':
                    label = 'B'
                    score = (score + score_p) / 2
                label_p = None
                num_b += 1

            if conf.do_apply_sigmoid:
                score = 1.0 / (1.0 + math.exp(-1.0 * score)) # --- sigmoid
                
        prob_id = data_list[i-num_b].attr['id']
        out.append('%s %s %5.3lf' % (prob_id, label, score))

    return '\n'.join(out)


# -----------------------------------------------------------------------------
# train the model with data_list.
# -----------------------------------------------------------------------------
def train(data_list):
    global fn_dev_f, fn_test_f, fn_model, fn_dev_log, fn_test_log

    initialize()
    data_type = conf.getDataType(conf.filename_dev)
    
    # make feature file
    feature.writeFeatures(fn_dev_f, data_list)

    print 'start training:'
    print '-' * 40

    opt_p = ''
    for key, value in conf.params.iteritems():
        opt_p += ' -p %s=%s' % (key, value)
    opt_p = opt_p.strip()

    command = 'classias-train %s -a %s -m %s %s %s | tee %s' % \
              ( ('-tb' if data_type=='bc' else '-tn'),
                conf.algorithm, fn_model, opt_p, fn_dev_f, fn_dev_log )

    os.system(command)

    print '-' * 40
    print 'complete training.'


# -----------------------------------------------------------------------------
# execute tagging and output result.
# -----------------------------------------------------------------------------
def test(data_list):
    global fn_dev_f, fn_test_f, fn_model, fn_dev_log, fn_test_log
    
    print 'start test:'
    print '-' * 40

    data_type = conf.getDataType(fn_test_f)
    
    # make feature file
    feature.writeFeatures(fn_test_f, data_list)

    command = 'cat %s | classias-tag -m %s -w' % (fn_test_f, fn_model)
    out = commands.getoutput(command)

    result = convertClassias2RITE( out, data_list, (data_type=='mc') )
    with open(fn_test_log, 'w') as fo:
        fo.write(result)
    
    print '-' * 40
    print 'complete test.'


# -----------------------------------------------------------------------------
# do cross-validations
# -----------------------------------------------------------------------------
def crossvalidate():
    global fn_dev_f, fn_test_f, fn_model, fn_dev_log, fn_test_log

    initialize()
    data_type = conf.getDataType(conf.filename_dev)
    
    DIR = conf.log_dir_name
    SEP = conf.sep_num
    
    # read xml files
    data_list = conf.getDevData()
    size      = len(data_list) / SEP

    for i in xrange(SEP):
        fn_feat = '%s/cross_%d.f' % (DIR, i)

        if i < SEP-1:
            data = data_list[size*i:size*(i+1)]
        else:
            data = data_list[size*i:]

        feature.writeFeatures(fn_feat, data)

    print 'start cross-validation :'
    print '-' * 40

    result_rite_list = []

    for i in xrange(SEP):
        print 'cross-validation (%d/%d):' % (i+1, SEP)
        print '-' * 40
        
        fn_dev_f    = [ '%s/cross_%d.f' % (DIR, j) for j in xrange(SEP) if j!=i ]
        fn_test_f   = '%s/cross_%d.f'        % (DIR, i)
        fn_model    = '%s/cross_%d.model'    % (DIR, i)
        fn_dev_log  = '%s/cross_%d_dev.log'  % (DIR, i)
        fn_test_log = '%s/cross_%d_test.log' % (DIR, i)

        command = 'classias-train %s -a %s -m %s %s | tee %s' % \
                  ( ('-tb' if data_type=='bc' else '-tn'),
                    conf.algorithm, fn_model, ' '.join(fn_dev_f), fn_dev_log )
        os.system( command )

        out = commands.getoutput(
            'cat %s | classias-tag -m %s -w' % (fn_test_f, fn_model))

        if i < SEP-1: data = data_list[size*i:size*(i+1)];
        else:         data = data_list[size*i:];
        
        result_rite = convertClassias2RITE(out, data, (data_type=='mc'))
        result_rite_list.append(result_rite)

        with open(fn_test_log, 'w') as fo:
            fo.write(result_rite)

        if i < SEP - 1:
            print '-' * 40

    print '-' * 40
    print 'complete cross-validation.'

    fn_log = '%s/cross_test_all.log' % DIR
    with open(fn_log, 'w') as fo:
        fo.write('\n'.join(result_rite_list))
    


